home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / fpu881 / src6.zoo / scanf.c < prev    next >
C/C++ Source or Header  |  1991-09-24  |  8KB  |  429 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3.     
  4. /*
  5.  * %efg were loosing big time
  6.  *    fixed  ++jrb
  7.  * all floating conversion now done by atof. much is gained by this.
  8.  *    ++jrb
  9.  */
  10.     
  11. #ifndef __NO_FLOAT__
  12. #define FLOATS 1
  13. #endif
  14.     
  15. #ifndef TRUE
  16. #define TRUE  1
  17. #define FALSE 0
  18. #endif
  19.     
  20. extern        char    _numstr[];
  21.  
  22. #define    skip()    while(isspace(c)) { if ((c=(*get)(ip))<1) goto done; }
  23. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  24.  
  25. #if FLOATS
  26. /* fp scan actions */
  27. #define F_NADA    0    /* just change state */
  28. #define F_SIGN    1    /* set sign */
  29. #define F_ESIGN    2    /* set exponent's sign */
  30. #define F_INT    3    /* adjust integer part */
  31. #define F_FRAC    4    /* adjust fraction part */
  32. #define F_EXP    5    /* adjust exponent part */
  33. #define F_QUIT    6
  34.  
  35. #define NSTATE    8
  36. #define FS_INIT        0    /* initial state */
  37. #define FS_SIGNED    1    /* saw sign */
  38. #define FS_DIGS        2    /* saw digits, no . */
  39. #define FS_DOT        3    /* saw ., no digits */
  40. #define FS_DD        4    /* saw digits and . */
  41. #define FS_E        5    /* saw 'e' */
  42. #define FS_ESIGN    6    /* saw exp's sign */
  43. #define FS_EDIGS    7    /* saw exp's digits */
  44.  
  45. #define FC_DIG        0
  46. #define FC_DOT        1
  47. #define FC_E        2
  48. #define FC_SIGN        3
  49.  
  50. /* given transition,state do what action? */
  51. int fp_do[][NSTATE] = {
  52. {F_INT,F_INT,F_INT,
  53.      F_FRAC,F_FRAC,
  54.      F_EXP,F_EXP,F_EXP},    /* see digit */
  55. {F_NADA,F_NADA,F_NADA,
  56.      F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT},    /* see '.' */
  57. {F_QUIT,F_QUIT,
  58.      F_NADA,F_QUIT,F_NADA,
  59.      F_QUIT,F_QUIT,F_QUIT},    /* see e/E */
  60. {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
  61.      F_ESIGN,F_QUIT,F_QUIT},    /* see sign */
  62. };
  63. /* given transition,state what is new state? */
  64. int fp_ns[][NSTATE] = {
  65. {FS_DIGS,FS_DIGS,FS_DIGS,
  66.      FS_DD,FS_DD,
  67.      FS_EDIGS,FS_EDIGS,FS_EDIGS},    /* see digit */
  68. {FS_DOT,FS_DOT,FS_DD,
  69.  },    /* see '.' */
  70. {0,0,
  71.      FS_E,0,FS_E,
  72.  },    /* see e/E */
  73. {FS_SIGNED,0,0,0,0,
  74.      FS_ESIGN,0,0},    /* see sign */
  75. };
  76. /* which states are valid terminators? */
  77. int fp_sval[NSTATE] = {
  78.     0,0,1,0,1,0,0,1
  79. };
  80. #endif
  81.  
  82. _scanf(ip, get, unget, fmt, args)
  83. register unsigned char *ip;
  84. int (*get)();
  85. int (*unget)();
  86. register unsigned char *fmt;
  87. char **args;
  88.  
  89. {
  90.     register long n;
  91.     register int c, width, lval, sval, cnt = 0;
  92.     int store, neg, base, wide1, endnull, rngflag, c2;
  93.     register unsigned char *p;
  94.     unsigned char delim[128], digits[17], *q;
  95.     char *strchr(), *strcpy();
  96. #if FLOATS
  97.     double fx;
  98.     char fbuf[128], *fbp;
  99.     int fstate, trans;
  100.     extern double atof();
  101. #endif
  102.     
  103.     if (!*fmt)
  104.     return(0);
  105.     
  106.     c = (*get)(ip);
  107.     while(c > 0)
  108.     {
  109.     store = FALSE;
  110.     if (*fmt == '%')
  111.     {
  112.         n    = 0;
  113.         width    = -1;
  114.         wide1    = 1;
  115.         base    = 10;
  116.         lval    = FALSE;
  117.         sval    = FALSE;
  118.         store    = TRUE;
  119.         endnull    = TRUE;
  120.         neg    = -1;
  121.         
  122.         strcpy(delim,  "\011\012\013\014\015 ");
  123.         strcpy(digits, _numstr); /* "01234567890ABCDEF" */
  124.         
  125.         if (fmt[1] == '*')
  126.         {
  127.         endnull = store = FALSE;
  128.         ++fmt;
  129.         }
  130.         
  131.         while (isdigit(*++fmt))        /* width digit(s) */
  132.         {
  133.         if (width == -1)
  134.             width = 0;
  135.         wide1 = width = TEN_MUL(width) + (*fmt - '0');
  136.         }
  137.         --fmt;
  138.       fmtnxt:
  139.         ++fmt;
  140.         switch(tolower(*fmt))    /* tolower() is a MACRO! */
  141.         {
  142.           case '*':
  143.         endnull = store = FALSE;
  144.         goto fmtnxt;
  145.         
  146.           case 'l':    /* long data */
  147.         lval = TRUE;
  148.           case 'h':    /* short data (for compatibility) */
  149.         sval = TRUE;
  150.         goto fmtnxt;
  151.         
  152.           case 'i':    /* any-base numeric */
  153.         base = 0;
  154.         goto numfmt;
  155.         
  156.           case 'b':    /* unsigned binary */
  157.         base = 2;
  158.         goto numfmt;
  159.         
  160.           case 'o':    /* unsigned octal */
  161.         base = 8;
  162.         goto numfmt;
  163.         
  164.           case 'x':    /* unsigned hexadecimal */
  165.         base = 16;
  166.         goto numfmt;
  167.         
  168.           case 'd':    /* SIGNED decimal */
  169.         neg = FALSE;
  170.         /* FALL-THRU */
  171.         
  172.           case 'u':    /* unsigned decimal */
  173.           numfmt:                    skip();
  174.         
  175.         if (isupper(*fmt))
  176.             lval = TRUE;
  177.         
  178.         if (!base)
  179.         {
  180.             base = 10;
  181.             neg = FALSE;
  182.             if (c == '%')
  183.             {
  184.             base = 2;
  185.             goto skip1;
  186.             }
  187.             else if (c == '0')
  188.             {
  189.             c = (*get)(ip);
  190.             if (c < 1)
  191.                 goto savnum;
  192.             if ((c != 'x')
  193.                 && (c != 'X'))
  194.             {
  195.                 base = 8;
  196.                 digits[8]= '\0';
  197.                 goto zeroin;
  198.             }
  199.             base = 16;
  200.             goto skip1;
  201.             }
  202.         }
  203.         
  204.         if ((neg == FALSE) && (base == 10)
  205.             && ((neg = (c == '-')) || (c == '+')))
  206.         {
  207.           skip1:
  208.             c = (*get)(ip);
  209.             if (c < 1)
  210.             goto done;
  211.         }
  212.         
  213.         digits[base] = '\0';
  214.         p = ((unsigned char *)
  215.              strchr(digits,toupper(c)));
  216.         
  217.         if ((!c || !p) && width)
  218.             goto done;
  219.         
  220.         while (p && width-- && c)
  221.         {
  222.             n = (n * base) + (p - digits);
  223.             c = (*get)(ip);
  224.           zeroin:
  225.             p = ((unsigned char *)
  226.              strchr(digits,toupper(c)));
  227.         }
  228.           savnum:
  229.         if (store)
  230.         {
  231.             p = ((unsigned char *) *args);
  232.             if (neg == TRUE)
  233.             n = -n;
  234.             if (lval)
  235.             *((long*) p) = n;
  236.             else if (sval)
  237.             *((short *) p) = n;
  238.             else
  239.             *((int *) p) = n;
  240.             ++cnt;
  241.         }
  242.         break;
  243.         
  244. #if FLOATS
  245.           case 'e':    /* float */
  246.           case 'f':
  247.           case 'g':
  248.         skip();
  249.         
  250.         if (isupper(*fmt))
  251.             lval = TRUE;
  252.         
  253.         fstate = FS_INIT;
  254.         fbp = fbuf;
  255.         while (c && width--) {
  256.             if (c >= '0' && c <= '9')
  257.             trans = FC_DIG;
  258.             else if (c == '.')
  259.             trans = FC_DOT;
  260.             else if (c == '+' || c == '-')
  261.             trans = FC_SIGN;
  262.             else if (tolower(c) == 'e')
  263.             trans = FC_E;
  264.             else
  265.             goto fdone;
  266.             
  267.             *fbp++ = c;
  268.  
  269.             if (fp_do[trans][fstate] == F_QUIT)
  270.             goto fdone;
  271.             fstate = fp_ns[trans][fstate];
  272.             c = (*get)(ip);
  273.         }
  274.         
  275.           fdone:
  276.         *fbp = '\0';
  277.         if (!fp_sval[fstate])
  278.             goto done;
  279.         if (store) {
  280.             fx = (*fbuf == '\0') ? 0.0 : atof(fbuf);
  281.             p = (unsigned char *) *args;
  282.             if (lval)
  283.             *((double *) p) = fx;
  284.             else
  285.             *((float *) p) = (float)fx;
  286.             ++cnt;
  287.         }
  288.         break;
  289. #endif
  290.         
  291.           case 'n':
  292.         if (store) {
  293.           p = (unsigned char *) *args;
  294.           *((int *) p) = cnt;
  295.         }
  296.         break;
  297.         
  298.           case 'c':    /* character data */
  299.         width = wide1;
  300.         endnull    = FALSE;
  301.         delim[0] = '\0';
  302.         goto strproc;
  303.         
  304.           case '[':    /* string w/ delimiter set */
  305.         
  306.         /* get delimiters */
  307.         p = delim;
  308.         
  309.         if (*++fmt == '^')
  310.             fmt++;
  311.         else
  312.             lval = TRUE;
  313.         
  314.         rngflag = 2;
  315.         if ((*fmt == ']') || (*fmt == '-'))
  316.         {
  317.             *p++ = *fmt++;
  318.             rngflag = FALSE;
  319.         }
  320.         
  321.         while (*fmt != ']')
  322.         {
  323.             if (*fmt == '\0')
  324.             goto done;
  325.             switch (rngflag)
  326.             {
  327.               case TRUE:
  328.             c2 = *(p-2);
  329.             if (c2 <= *fmt)
  330.             {
  331.                 p -= 2;
  332.                 while (c2 < *fmt)
  333.                 *p++ = c2++;
  334.                 rngflag = 2;
  335.                 break;
  336.             }
  337.             /* fall thru intentional */
  338.             
  339.               case FALSE:
  340.             rngflag = (*fmt == '-');
  341.             break;
  342.             
  343.               case 2:
  344.             rngflag = FALSE;
  345.             }
  346.             
  347.             *p++ = *fmt++;
  348.         }
  349.         
  350.         *p = '\0';
  351.         goto strproc;
  352.         
  353.           case 's':    /* string data */
  354.         skip();
  355.           strproc:
  356.         /* process string */
  357.         p = ((unsigned char *) *args);
  358.         
  359.         /* if the 1st char fails, match fails */
  360.         if (width)
  361.         {
  362.             q = ((unsigned char *)
  363.              strchr(delim, c));
  364.             if((c < 1)
  365.                || (lval ? !q : (int) q))
  366.             {
  367.             if (endnull)
  368.                 *p = '\0';
  369.             goto done;
  370.             }
  371.         }
  372.         
  373.         for (;;) /* FOREVER */
  374.         {
  375.             if (store)
  376.             *p++ = c;
  377.             if (((c = (*get)(ip)) < 1) ||
  378.             (--width == 0))
  379.             break;
  380.             
  381.             q = ((unsigned char *)
  382.              strchr(delim, c));
  383.             if (lval ? !q : (int) q)
  384.             break;
  385.         }
  386.         
  387.         if (store)
  388.         {
  389.             if (endnull)
  390.             *p = '\0';
  391.             ++cnt;
  392.         }
  393.         break;
  394.         
  395.           case '\0':    /* early EOS */
  396.         --fmt;
  397.         /* FALL THRU */
  398.         
  399.           default:
  400.         goto cmatch;
  401.         }
  402.     }
  403.     else if (isspace(*fmt))        /* skip whitespace */
  404.     {
  405.         skip();
  406.     }
  407.     else 
  408.     {            /* normal match char */
  409.       cmatch:
  410.         if (c != *fmt) 
  411.         break;
  412.         c = (*get)(ip);
  413.     }
  414.     
  415.     if (store)
  416.         args++;
  417.     
  418.     if (!*++fmt)
  419.         break;
  420.     }
  421.     
  422.   done:                        /* end of scan */
  423.     if ((c < 0) && (cnt == 0))
  424.     return(EOF);
  425.     
  426.     (*unget)(c, ip);
  427.     return(cnt);
  428. }
  429.